<?php
namespace app\common;

use Yii;
use common\widgets\Tools;
use common\TrySafe;
/**
 * 短信通知
 *
 * @author Terry<admin@huicms.cn> 2016-05-19
 * @version 1.0
 */
class EasySMS {
	const MAX_TRIES = 10;

	public $account = '';
	public $pswd = '';
	public $_message = [
		'0' => '发送成功',
		'101' => '账号不存在',
		'102' => '密码错误',
		'103' => '提交请求太快',
		'104' => '系统忙',
		'105' => '含有敏感危险词',
		'106' => '消息长度错（>536或<=0）',
		'107' => '包含错误的手机号码',
		'108' => '手机号码个数错（群发>50000或<=0;单发>200或<=0）',
		'109' => '无发送额度（该用户可用短信数已使用完）',
		'110' => '不在发送时间内',
		'111' => '超出该账户当月发送额度限制',
		'112' => '无此产品，用户没有订购该产品',
		'113' => 'extno格式错（非数字或者长度不对）',
		'115' => '自动审核驳回',
		'116' => '签名不合法，未带签名（用户必须带签名的前提下）',
		'117' => 'IP地址认证错,请求调用的IP地址不是系统登记的IP地址',
		'118' => '用户没有相应的发送权限',
		'119' => '用户已过期',
		'120' => '短信内容不在白名单中',

		'9002' => '未知命令',
		'9012' => '短信消息内容错误',
		'9013' => '目标地址错误',
		'9014' => '短信内容太长',
		'9015' => '路由错误',
		'9016' => '没有下发网关',
		'9017' => '定时时间错误',
		'9018' => '有效时间错误',
		'9019' => '无法拆分或者拆分错误',
		'9020' => '号码段错误',
		'9021' => '消息编号错误，这个和PacketIndex参数有关',
		'9101' => '验证失败，一般和用户名/密码/IP地址相关',
		'9102' => '没有填写用户名',
		'9103' => '名字没找到',
		'9104' => 'IP地址不对',
		'9105' => '超过最大连接数，就是tcp连接数，http也是一样的',
		'9106' => '协议版本错误',
	];

	public function __construct() {
		$this->account = \Yii::$app->params['sms']['account'];
		$this->pswd = \Yii::$app->params['sms']['pswd'];
	}

	private $captcha_titles = [
		'register' => '该手机号正在注册缳亚医学康复，',
	];

	/**
	 * 发送短信
	 *
	 * @param string $str_mobile
	 *        	手机号
	 * @param string $tpl_flag
	 *        	模板名称
	 * @param array $ary_tpl_data
	 *        	模板参数
	 * @param string $version
	 * 			键后缀
	 * @return $ary_result {"status":200,"msg":””} 成功
	 *         {"status”:500,"msg":””} 错误
	 *         {"status":501,"msg":””} 重复发送
	 *         {"status":502,"msg":””} 发送次数超限
	 *         {"status":503,"msg":””} 模版不正确
	 *         {"status":504,"msg":””} 发送失败
	 *         {"status":505,"msg":”"} 余额不足
	 * @author Terry<admin@huicms.cn> 2016-05-19
	 * @version 1.0
	 */
	public function send($str_mobile, $tpl_flag, $ary_tpl_data = [ ], $version = '') {
		$ary_result = [
			'status' => '0',
			'msg' => '发送成功'
		];
		$appKey = '';
		switch ($tpl_flag) {
			case 'huanya_verify_code':
				$int_code = rand ( '100000', '999999' );
				$key = $this->getVerifyCodeKey($str_mobile, $version);
				Tools::setOCS ( $key, $int_code, 30 * 60 );
				$str_content = "您的验证码是:".$int_code."，（平台验证码，30分钟内有效）请勿将验证码泄漏给其他人。";
				$appKey = 'true';
				break;
			case 'h5_huanya_verify_code':
				$int_code = rand ( '100000', '999999' );
				$key = $this->getVerifyCodeKey($str_mobile, $version);
				Tools::setOCS ( $key, $int_code, 30 * 60 );
				$str_content = "您的验证码是:".$int_code."，（平台验证码，30分钟内有效）请勿将验证码泄漏给其他人。";
				$appKey = 'captcha';
				break;
			case 'certifies_audit_success':
				$str_content = '恭喜您提交的资料已经通过审核';
				$appKey = 'certifies.audit.success';
				break;
			case 'certifies_audit_refuse':
				$str_content = $ary_tpl_data['content'];
				$appKey = 'certifies.audit.refuse';
				break;
			case 'send_member_message':
				$str_content = $ary_tpl_data['content'];
				$appKey = 'send.member.message';
				break;
			case 'member_audit_success':
				$str_content = '恭喜您提交的资料已经通过审核';
				$appKey = 'member.audit.success';
				break;
			case 'add_order_success_message':
				$str_content = $ary_tpl_data['content'];
				$appKey = 'add.order.success.message';
				break;
			default:
				break;
		}

		if (false == empty ( $tpl_flag )) {
			$arr_result = $this->sendVerifyCodeSMS($str_mobile,$str_content,$appKey);
			if(false == empty($arr_result)) {
				$str_result = str_replace("\n", "", $arr_result);
				$send_result = explode(",", $str_result);
				$int_code = $send_result[1];
				$ary_result['status'] = $int_code;
				$ary_result['msg'] = $this->_message[$int_code];
				$this->setVerifyCodeErrorMessage($this->_message[$int_code]);
			}
		}
		return $ary_result;
	}

	/**
	 * 获取校验重试安全类
	 * @return TrySafe
	 */
	public function getCheckTrySafe($key)
	{
		static $tries = [];
		if(isset($tries[$key]) == false) {
			$tries[$key] = new TrySafe([
				'key' => 'smsCode/check/'.$key,
				'prefix' => '短信验证码',
			]);
		}
		return $tries[$key];
	}

	/**
	 * 获取校验重试安全类
	 * @return TrySafe
	 */
	public function getSendTrySafe($key)
	{
		static $tries = [];
		if(isset($tries[$key]) == false) {
			$tries[$key] = new TrySafe([
				'key' => 'smsCode/send/'.$key,
				'prefix' => '短信验证码',
				'blockMessage' => '%s已连续发送%s次，暂时冻结，请%s后再试！',
			]);
		}
		return $tries[$key];
	}

	/**
	 * 获取短信验证码的缓存key
	 *
	 * @param $str_mobile
	 * @param $version
	 * @return string
	 */
	public function getVerifyCodeKey($str_mobile, $version)
	{
		$key = 'huanya_verify_code_' . $str_mobile;
		if($version) $key .= '_'.$version;
		return $key;
	}

	/**
	 * 发送验证码
	 *
	 * @param $str_mobile
	 * @param string $version
	 * @return int 1=成功发送，-1=不允许发送
	 */
	public function sendVerifyCode($str_mobile, $version = '')
	{
		$suffix = $version ? '_'.$version : $version;
		// 校验短信验证码连续发送但没一次校验通过（不区分场景）
		$sendTrySafe = $this->getSendTrySafe($str_mobile);
		if(!$sendTrySafe->check()) {
			$this->setVerifyCodeErrorMessage($sendTrySafe->getErrorMessage());
			return -1;
		}
		// 递增次数
		$sendTrySafe->incr();

		// 校验短信验证码校验失败次数（区分场景）
		$checkTrySafe = $this->getCheckTrySafe($str_mobile.$suffix);
		if(!$checkTrySafe->check()) {
			$this->setVerifyCodeErrorMessage($checkTrySafe->getErrorMessage());
			return -1;
		}

		$this->send($str_mobile, 'huanya_verify_code', [], $version);
		return 1;
	}

	/**
	 * 获取已发送的验证码
	 */
	public function getVerifyCode($str_mobile, $version = '') {
		return Tools::getOCS ( $this->getVerifyCodeKey($str_mobile, $version) );
	}

	/**
	 * 删除验证码
	 */
	public function deleteVerifyCode($str_mobile, $version = '')
	{
		return Tools::deleteOCS($this->getVerifyCodeKey($str_mobile, $version));
	}

	/**
	 * 验证验证码
	 * @param string $str_mobile
	 * @param number $int_code
	 * @param string $version
	 * @param boolean $isRefresh
	 * @return 1=正常，-1=错误，-2=半小时内错误次数过多
	 */
	public function checkVerifyCode($str_mobile, $int_code, $version = '', $isRefresh = true) {
		$suffix = $version ? '_'.$version : $version;

		$trySafe = $this->getCheckTrySafe($str_mobile.$suffix);
		if(!$trySafe->check()) {
			$this->setVerifyCodeErrorMessage($trySafe->getErrorMessage());
			return -2;
		}

		// 获取验证码
		$ret = $int_code && $int_code == $this->getVerifyCode($str_mobile, $version);
		if($ret == false) {
			// 校验失败，记录失败次数
			$trySafe->incr();
			$this->setVerifyCodeErrorMessage($trySafe->getErrorMessage());
			return -1;
		}else{
			// 校验成功，且说明清除，则删除验证码和重试次数
			if($isRefresh)
			{
				// 删除老验证码
				$this->deleteVerifyCode($str_mobile, $version);
				// 清除发送重试限制
				$this->getSendTrySafe($str_mobile)->reset();
				// 清除校验重试限制
				$trySafe->reset();
			}
			return 1;
		}
	}

	private $_verifyCodeErrorMessage = '';

	/**
	 * 设置验证码信息
	 */
	public function setVerifyCodeErrorMessage($msg)
	{
		$this->_verifyCodeErrorMessage = $msg;
	}

	/**
	 * 验证码错误信息
	 * @return string
	 */
	public function getVerifyCodeErrorMessage()
	{
		return $this->_verifyCodeErrorMessage;
	}

	/**
	 * 专门负责发送手机验证码 方法
	 * @param $str_mobile
	 * @param $int_code
	 */
	public function sendVerifyCodeSMS($str_mobile, $str_content,$appKey = '')
	{
		$smsParam = [
			"account"=> $this->account,
			'pswd' => $this->pswd,
			'mobile' => $str_mobile,
			'msg' => $str_content,
			'needstatus' => true,
		];
		$ary_result = Tools::api ( 'msg/HttpBatchSendSM', $smsParam, 'smscode' ,'GET');
		return $ary_result;
	}
}